trying URL 'http://cran.us.r-project.org/bin/macosx/contrib/4.0/maps_3.3.0.tgz'
Content type 'application/x-gzip' length 3687860 bytes (3.5 MB)
==================================================
downloaded 3.5 MB

The downloaded binary packages are in
    /var/folders/gs/080wb67j58df5y8ccjf53yw00000gn/T//RtmpcHXjz6/downloaded_packages
trying URL 'http://cran.us.r-project.org/bin/macosx/contrib/4.0/tmap_3.3-1.tgz'
Content type 'application/x-gzip' length 3585561 bytes (3.4 MB)
==================================================
downloaded 3.4 MB

The downloaded binary packages are in
    /var/folders/gs/080wb67j58df5y8ccjf53yw00000gn/T//RtmpcHXjz6/downloaded_packages
trying URL 'http://cran.us.r-project.org/bin/macosx/contrib/4.0/rgeos_0.5-5.tgz'
Content type 'application/x-gzip' length 8537441 bytes (8.1 MB)
==================================================
downloaded 8.1 MB

The downloaded binary packages are in
    /var/folders/gs/080wb67j58df5y8ccjf53yw00000gn/T//RtmpcHXjz6/downloaded_packages
# Set the WD as Group_G_HigherEd 
setwd("~/Dropbox (Business)/Spring 2021/QMSS 5063 - Data Visualization /Group_G_HigherEd")

# While our initial College Scorecard only included 2019 initially, I was able to run a simple python script to concatenate and select a small number of relevant columns for our visualization and analysis. Thus, as our first visualizations only unclude 2019, the code below is for re-filtering the concatenated 2010-2019 data back into simply 2019. 

sc_time <- read_csv('src/2010_2019_student_debt.csv') 
sc <- sc_time %>% filter(Year_Ending == 2019)

library(educationdata)
# Test Run with using get_education_data 
# data <- get_education_data(level = "college-university",
#     source = "ipeds",
#     topic = "directory",
#     filters = list(year = 2019))
# data
# Scorecard data - 2019 

## change projection of sc data
sc <- sc %>%
  dplyr::mutate(uni_rank = case_when(
    ADM_RATE < 0.2 ~ 'highly selective/elite',
    ADM_RATE < 0.3 ~ 'more selective',
    ADM_RATE < 0.5 ~ 'selective',
    ADM_RATE < 0.7 ~ 'less selective',
    TRUE ~ 'not selective')) %>% mutate(uni_rank = factor(uni_rank, levels=c('not selective', 'less selective', 'selective', 'more selective', 'highly selective/elite')))

Simple Scattergram

First we are going to try to present this pattern for different tiers of universities (admission rate as well as debt)

# Remove PrivacySuppressed Records and transform Debt Median into a numeric value - we can also do this on the main sc df
sc$DEBT_MDN[is.na(sc$DEBT_MDN)] <- 0;

brewer.pal(n=10,"PuBuGn")
n too large, allowed maximum for palette PuBuGn is 9
Returning the palette you asked for with that many colors
[1] "#FFF7FB" "#ECE2F0" "#D0D1E6" "#A6BDDB" "#67A9CF" "#3690C0" "#02818A" "#016C59" "#014636"
ShortPuBuGn <- c("#D0D1E6","#A6BDDB","#67A9CF","#3690C0","#02818A")

m <- sc %>% subset(DEBT_MDN !='PrivacySuppressed') %>% transform(DEBT_MDN = as.numeric(DEBT_MDN)) %>% 
              ggplot(., aes(x=ADM_RATE, y=DEBT_MDN,color=uni_rank)) +
  geom_point(pch=21) +
  geom_smooth(color='navy', se = FALSE) +
  scale_color_manual(values=ShortPuBuGn)+
  theme(
    panel.grid.major = element_blank(),
    panel.grid.minor = element_blank(),
    panel.background= element_rect(fill="white")) +
  scale_y_discrete(limits=c(0,10000,20000,30000), labels=c('0','10','20','30')) +
  labs(x='Admissions Rate', y='Median Loan Amount per Student\n(thousands)', 
       title='Student Debt and Admissions Rate',
       color='Selectivity')
Continuous limits supplied to discrete scale.
Did you mean `limits = factor(...)` or `scale_*_continuous()`?
m

This is a data table showing the breakdown of the university ranks (as I chose to rank them). I will note that from the dt alone wwe are seeing a downward trend in the ‘Median Student Loans’ column.

# Create Data Table (Summarized) for 
library('scales')

Attaching package: ‘scales’

The following object is masked from ‘package:viridis’:

    viridis_pal

The following object is masked from ‘package:purrr’:

    discard

The following object is masked from ‘package:readr’:

    col_factor
sc_dt <- sc %>% subset(DEBT_MDN !='PrivacySuppressed') %>% transform(DEBT_MDN = as.numeric(DEBT_MDN)) %>% group_by(uni_rank) %>% mutate(`Number of Universities` = n()) %>% ungroup() %>% mutate(DEBT_MDN_STUDENTS = DEBT_MDN*UGDS) %>% group_by(uni_rank) %>% mutate(`Median Student Loans` = paste('$',round(sum(DEBT_MDN_STUDENTS, na.rm=TRUE)/sum(UGDS, na.rm=TRUE),2))) %>% 
  mutate(`Min Acceptance Rate` = percent(min(ADM_RATE))) %>% mutate(`Max Acceptance Rate` = percent(max(ADM_RATE))) %>% ungroup() %>% 
  group_by(uni_rank,`Median Student Loans`,`Number of Universities`,`Min Acceptance Rate`,`Max Acceptance Rate`) %>% 
  summarize()
`summarise()` regrouping output by 'uni_rank', 'Median Student Loans', 'Number of Universities', 'Min Acceptance Rate' (override with `.groups` argument)
install.packages('DT')
Installing package into ‘/Users/ConnieXu/Library/R/4.0/library’
(as ‘lib’ is unspecified)
trying URL 'http://cran.us.r-project.org/bin/macosx/contrib/4.0/DT_0.18.tgz'
Content type 'application/x-gzip' length 1678529 bytes (1.6 MB)
==================================================
downloaded 1.6 MB

The downloaded binary packages are in
    /var/folders/gs/080wb67j58df5y8ccjf53yw00000gn/T//RtmpcHXjz6/downloaded_packages
library(DT)
table <- datatable(sc_dt,style = "default",filter = 'top',  caption = 'Universities and Selectivity')
table
NA
install.packages('treemap')
install.packages('highcharter')
library(highcharter)
library(treemap)

sc_dt %>% 
  treemap(index="uni_rank",
          vSize="Number of Universities",
        type="index",
        fontsize.labels=c(12, 8), 
        palette =  viridis(5),
        border.col="white",
        title = 'Universities and Selectivity')

Scattergram as Violin Plot

m <- sc %>% subset(DEBT_MDN !='PrivacySuppressed') %>% transform(DEBT_MDN = as.numeric(DEBT_MDN)) %>% 
  ggplot(., aes(x=uni_rank, y=DEBT_MDN)) +
  geom_violin(aes(fill=uni_rank,color=uni_rank)) +
  geom_boxplot(width = 0.2)+
  scale_fill_manual(values=ShortPuBuGn) +
  scale_colour_manual(values=ShortPuBuGn) +
  theme(
    panel.grid.major = element_blank(),
    panel.grid.minor = element_blank(),
    panel.background= element_rect(fill="white"))+
  scale_y_discrete(limits=c(0,10000,20000,30000), labels=c('0','10','20','30')) +
  scale_x_discrete(labels=c('not\nselective\n(>70%)','less\nselective\n(50%-70%)',
                            'selective\n(30%-50%)','more\nselective\n(20%-30%)','highly\nselective\n(5%-20%)','elite\n(<5%)')) +

  labs(x='Selectivity\n(admission rate thresholds)', y='Median Loan Amount per Student\n(thousands)', 
       title='Selective Schools and Student Debt',
       color='',fill='')
Continuous limits supplied to discrete scale.
Did you mean `limits = factor(...)` or `scale_*_continuous()`?
m

Showing the previous scattergram specifically as violing plots

m <- sc %>% subset(DEBT_MDN !='PrivacySuppressed') %>% transform(DEBT_MDN = as.numeric(DEBT_MDN)) %>% 
  ggplot(., aes(x=uni_rank, y=DEBT_MDN)) +
  geom_violin(aes(fill=uni_rank,color=uni_rank)) +
  geom_boxplot(width = 0.2)+
  scale_fill_manual(values=ShortPuBuGn) +
  scale_colour_manual(values=ShortPuBuGn) +
  theme(
    panel.grid.major = element_blank(),
    panel.grid.minor = element_blank(),
    panel.background= element_rect(fill="white"))+
  scale_y_discrete(limits=c(0,10000,20000,30000), labels=c('0','10','20','30')) +
  scale_x_discrete(labels=c('not\nselective\n(>70%)','less\nselective\n(50%-70%)',
                            'selective\n(30%-50%)','more\nselective\n(20%-30%)','highly\nselective\n(5%-20%)','elite\n(<5%)')) +

  labs(x='Selectivity\n(admission rate thresholds)', y='Median Loan Amount per Student\n(thousands)', 
       title='Selective Schools and Student Debt',
       color='',fill='')
Continuous limits supplied to discrete scale.
Did you mean `limits = factor(...)` or `scale_*_continuous()`?
m

Student Debt over Time


#Process the data 
sc_time <- read_csv('2010_2019_student_debt.csv') 

sc_time<- sc_time %>% subset(DEBT_MDN !='PrivacySuppressed') %>% 
  transform(DEBT_MDN = as.numeric(DEBT_MDN)) %>% 
  dplyr::mutate(DEBT_MDN = ifelse(is.na(DEBT_MDN), 0, DEBT_MDN))

#Process the data 
sc_time <- read_csv('2010_2019_student_debt.csv') 
Error: '2010_2019_student_debt.csv' does not exist in current working directory ('/Users/ConnieXu/Dropbox (Business)/Spring 2021/QMSS 5063 - Data Visualization /Group_G_HigherEd/ideas_drafts').

Below is an interactive line graph (2010-2019) which details the trends in student debt over the years.

#Process the data 
setwd("~/Dropbox (Business)/Spring 2021/QMSS 5063 - Data Visualization /Group_G_HigherEd")
The working directory was changed to /Users/ConnieXu/Dropbox (Business)/Spring 2021/QMSS 5063 - Data Visualization /Group_G_HigherEd inside a notebook chunk. The working directory will be reset when the chunk is finished running. Use the knitr root.dir option in the setup chunk to change the working directory for notebook chunks.
sc_time <- read_csv('src/2010_2019_student_debt.csv') 
Missing column names filled in: 'X1' [1]
── Column specification ────────────────────────────────────────────────────────────────────────────────────────────────────────
cols(
  .default = col_double(),
  INSTNM = col_character(),
  CITY = col_character(),
  STABBR = col_character(),
  ZIP = col_character(),
  UNEMP_RATE = col_logical(),
  DEBT_MDN = col_character(),
  MN_EARN_WNE_P10 = col_logical(),
  MD_EARN_WNE_P10 = col_logical(),
  School = col_logical(),
  State = col_logical(),
  True = col_character(),
  ADM_RATE_ALL_1 = col_character()
)
ℹ Use `spec()` for the full column specifications.

28660 parsing failures.
 row    col           expected                  actual                             file
3223 UNITID a double           Community College       'src/2010_2019_student_debt.csv'
3223 School 1/0/T/F/TRUE/FALSE Kenai Peninsula College 'src/2010_2019_student_debt.csv'
3223 State  1/0/T/F/TRUE/FALSE Alaska                  'src/2010_2019_student_debt.csv'
3224 UNITID a double           Community College       'src/2010_2019_student_debt.csv'
3224 School 1/0/T/F/TRUE/FALSE Kodiak College          'src/2010_2019_student_debt.csv'
.... ...... .................. ....................... ................................
See problems(...) for more details.
sc_time<- sc_time %>% subset(DEBT_MDN !='PrivacySuppressed') %>% 
  transform(DEBT_MDN = as.numeric(DEBT_MDN)) %>% 
  dplyr::mutate(DEBT_MDN = ifelse(is.na(DEBT_MDN), 0, DEBT_MDN)) %>% 
  mutate(DEBT_MDN_STUDENT = DEBT_MDN*UGDS)
sc_time

sum(sc_time$UGDS,na.rm=TRUE)
[1] 90801007

The following is (instead) a bar graph with fewer ‘university selectivity’ buckets.

# CPI Inflation Rates - Got Average Yearly Inflation Rate for Scaling for Student Debt 
install.packages('quantmod')
Error in install.packages : Updating loaded packages
library(quantmod)
getSymbols("CPIAUCSL", src='FRED')
[1] "CPIAUCSL"
install.packages("quantmod")
Installing package into ‘/Users/ConnieXu/Library/R/4.0/library’
(as ‘lib’ is unspecified)
trying URL 'http://cran.us.r-project.org/bin/macosx/contrib/4.0/quantmod_0.4.18.tgz'
Content type 'application/x-gzip' length 1028937 bytes (1004 KB)
==================================================
downloaded 1004 KB

The downloaded binary packages are in
    /var/folders/gs/080wb67j58df5y8ccjf53yw00000gn/T//RtmpPtXSjD/downloaded_packages
avg.cpi <- apply.yearly(CPIAUCSL, mean)
cf <- as.data.frame(avg.cpi/as.numeric(avg.cpi['2009'])) 
cf$Year_Ending <- format(as.Date(row.names(cf), format="%Y-%m-%d"),"%Y")

# Merged for Inflation 
sc_time_df <- sc_time %>% group_by(`Year_Ending`) %>% mutate(`Average Annual Student Debt - National` = sum(DEBT_MDN_STUDENT,na.rm=TRUE)/sum(UGDS,na.rm=TRUE)) %>% ungroup() %>% 
  dplyr::mutate(uni_rank = case_when(
    ADM_RATE < 0.2 ~ 'elite/highly selective',
    ADM_RATE < 0.3 ~ 'more selective',
    ADM_RATE < 0.5 ~ 'selective',
    ADM_RATE < 0.7 ~ 'less selective',
    TRUE ~ 'not selective')) %>%
  mutate(uni_rank = factor(uni_rank, levels=c('not selective', 'less selective', 'selective', 
                                              'more selective', 'elite/highly selective'))) %>%
  group_by(uni_rank,Year_Ending) %>% 
  mutate(`Average Annual Student Debt (by Selectivity)` = sum(DEBT_MDN_STUDENT,na.rm=TRUE)/sum(UGDS,na.rm=TRUE)) %>% 
  ungroup() %>% 
  group_by(`Year_Ending`,`Average Annual Student Debt (by Selectivity)`,
           uni_rank,`Average Annual Student Debt - National`) %>% summarize() %>% 
  merge(cf) %>% 
  mutate(`Adjusted Average Annual Student Debt` = `Average Annual Student Debt (by Selectivity)`/
           CPIAUCSL) %>% 
  mutate(`Adjusted Average Annual Student Debt - Composite` = `Average Annual Student Debt - National`/
           CPIAUCSL)
`summarise()` regrouping output by 'Year_Ending', 'Average Annual Student Debt (by Selectivity)', 'uni_rank' (override with `.groups` argument)
sc_df <- sc_time_df %>% group_by(`Average Annual Student Debt - National`,`Adjusted Average Annual Student Debt - Composite`,Year_Ending) %>% summarize() %>% mutate(uni_rank='national average') %>% mutate(`Adjusted Average Annual Student Debt`=`Adjusted Average Annual Student Debt - Composite`) %>% dplyr::mutate(`Average Annual Student Debt (by Selectivity)` = `Average Annual Student Debt - National`) %>% merge(cf) %>% select(Year_Ending,`Average Annual Student Debt (by Selectivity)`, uni_rank, `Average Annual Student Debt - National`, CPIAUCSL, `Adjusted Average Annual Student Debt`,`Adjusted Average Annual Student Debt - Composite`)
`summarise()` regrouping output by 'Average Annual Student Debt - National', 'Adjusted Average Annual Student Debt - Composite' (override with `.groups` argument)
sc_time_df <- sc_time_df %>% rbind(sc_df) %>% mutate(uni_rank = factor(uni_rank, levels=c('national average','not selective', 'less selective', 'selective', 'more selective', 'elite/highly selective'))) %>% 
  mutate(national = ifelse(uni_rank == 'national average', 'y','n'))
sc_df
sc_time_df


p <- sc_time_df %>% 
  ggplot(.,aes(x=Year_Ending,y=`Adjusted Average Annual Student Debt`, color=uni_rank, group=national)) + 
  geom_point() + geom_line(aes(linetype=national)) + 
  scale_color_manual(values=c('grey',"#D0D1E6","#A6BDDB","#67A9CF","#3690C0","#02818A"))+
  theme(
    panel.grid.major = element_blank(),
    panel.grid.minor = element_blank(),
    panel.background= element_rect(fill="white")) +
  scale_x_continuous(breaks = round(seq(min(sc_time$Year_Ending), max(sc_time$Year_Ending), by = 2),1)) +
  labs(x='', y='Inflation-Adjusted Median Loan Amount per Student\n(thousands)', 
       title='Student Debt Has Been Rising Over The Years',
       color='',fill='',group='',linetype='')
ggplotly(p)
NA
NA

Chloropleth showing average student debt (this is only 2019 but I have a filter at the beginning that will allow me to incorporate a slider for the year).

leaflet(states_2019) %>% addProviderTiles("CartoDB.Positron") %>%
  addPolygons(fillColor = ~pal(states_2019$`Average Student Loans`),
              color = "white",
              weight = 0.5,
              fillOpacity = 0.7,  
              highlight = highlightOptions(
                weight = 5,
                color = "#666",
                fillOpacity = 0.7,
                bringToFront = TRUE,
                ),popup=pop_pop) %>% addLegend(position = "bottomleft", colors =c("#EDF8E9","#BAE4B3","#74C476","#31A354","#006D2C"), 
                     labels = c(paste('$',round(min(states_2019$`Average Student Loans`)))," "," "," ", 
                                paste('$',round(max(states_2019$`Average Student Loans`)))),
            title = "Average Student Loans (Per Student)") %>%
  leaflet::setView(-98.5795, 39.8282, zoom=3) %>% addControl(states_2019_title, position='topright')
sf layer has inconsistent datum (+proj=longlat +datum=NAD83 +no_defs).
Need '+proj=longlat +datum=WGS84'n too large, allowed maximum for palette Greens is 9
Returning the palette you asked for with that many colors
brewer.pal(n = 8, name = "RdYlGn")
# last edit to sc_time_2019 in chunk above for chloropleth
sc_time_2019_selective <- sc_time_2019 %>% dplyr::rename(lat = LATITUDE) %>% dplyr::rename(long = LONGITUDE) %>% 
  dplyr::rename(state = STABBR) %>% filter(ADM_RATE < 0.3) %>% 
  dplyr::mutate(uni_rank = case_when(
    ADM_RATE < 0.05 ~ 'elite',
    ADM_RATE < 0.2 ~ 'highly selective',
    TRUE ~ 'selective'))
sc_time_2019_selective <- sc_time_2019_selective %>% subset(DEBT_MDN !='PrivacySuppressed') %>% 
  transform(DEBT_MDN = as.numeric(DEBT_MDN)) %>% 
  dplyr::mutate(DEBT_MDN = ifelse(is.na(DEBT_MDN), 0, DEBT_MDN)) 



pal1 = colorFactor(ShortPuBuGn, domain = sc_time_2019_selective$`uni_rank`,reverse=TRUE)
Error in force(palette) : object 'ShortPuBuGn' not found
setwd('~/Dropbox (Business)/Spring 2021/QMSS 5063 - Data Visualization /Group_G_HigherEd/')
sc_time <- read_csv('src/2010_2019_student_debt.csv') 
sc_time

The code chunk below has not been touched and includes Shiny code for later use.

setwd("~/Dropbox (Business)/Spring 2021/QMSS 5063 - Data Visualization /Group_G_HigherEd")
The working directory was changed to /Users/ConnieXu/Dropbox (Business)/Spring 2021/QMSS 5063 - Data Visualization /Group_G_HigherEd inside a notebook chunk. The working directory will be reset when the chunk is finished running. Use the knitr root.dir option in the setup chunk to change the working directory for notebook chunks.
sc_time <- read_csv('src/2010_2019_student_debt.csv') 
Missing column names filled in: 'X1' [1]
── Column specification ────────────────────────────────────────────────────────────────────────────────────────────────────────
cols(
  .default = col_double(),
  INSTNM = col_character(),
  CITY = col_character(),
  STABBR = col_character(),
  ZIP = col_character(),
  UNEMP_RATE = col_logical(),
  DEBT_MDN = col_character(),
  MN_EARN_WNE_P10 = col_logical(),
  MD_EARN_WNE_P10 = col_logical(),
  School = col_logical(),
  State = col_logical(),
  True = col_character(),
  ADM_RATE_ALL_1 = col_character()
)
ℹ Use `spec()` for the full column specifications.

28660 parsing failures.
 row    col           expected                  actual                             file
3223 UNITID a double           Community College       'src/2010_2019_student_debt.csv'
3223 School 1/0/T/F/TRUE/FALSE Kenai Peninsula College 'src/2010_2019_student_debt.csv'
3223 State  1/0/T/F/TRUE/FALSE Alaska                  'src/2010_2019_student_debt.csv'
3224 UNITID a double           Community College       'src/2010_2019_student_debt.csv'
3224 School 1/0/T/F/TRUE/FALSE Kodiak College          'src/2010_2019_student_debt.csv'
.... ...... .................. ....................... ................................
See problems(...) for more details.
sc_time<- sc_time %>% subset(DEBT_MDN !='PrivacySuppressed') %>% 
  transform(DEBT_MDN = as.numeric(DEBT_MDN)) %>% 
  dplyr::mutate(DEBT_MDN = ifelse(is.na(DEBT_MDN), 0, DEBT_MDN)) %>% 
  mutate(DEBT_MDN_STUDENT = DEBT_MDN*UGDS)
sc_time

library(reshape2)

Attaching package: ‘reshape2’

The following object is masked from ‘package:tidyr’:

    smiths
library(shiny)

Attaching package: ‘shiny’

The following objects are masked from ‘package:DT’:

    dataTableOutput, renderDataTable
ui <- fluidPage(
  titlePanel("I love Graphs about Student Debt"),
  # CODE BELOW: Add select input named "sex" to choose between "M" and "F"
  selectInput('year',
  'Year',
  choices=c(2010,2011,2012,2013,2014,2015,2016,2017,2018,2019)), 
  # Add plot output to display top 10 most popular names
  leafletOutput("studentdebtmap")
)

server <- function(input, output, session){
  # Render plot of top 10 most popular names
    sc_time_selective <- reactive({sc_time %>% subset(Year_Ending == input$year) %>% 
        group_by(STABBR) %>% mutate(`Average Student Loans`=sum(DEBT_MDN_STUDENT,na.rm=TRUE)/sum(UGDS,na.rm=TRUE)) %>%
        group_by(STABBR,`Average Student Loans`) %>% summarize()})
    library(tigris)
    states <- states(cb = TRUE)
    states_year <- reactive({states %>% inner_join(sc_time_selective(), by=c(STUSPS='STABBR'))}) 
    
  output$studentdebtmap <- renderLeaflet({
    pal = colorFactor('Greens', domain = states_year()$`Average Student Loans`)
    pop_pop <- paste("State:",states_year()$NAME,"<br/>",
                     "Average Student Loans","<br/>", "of Schools Located in State:",
                     paste('$',round(states_year()$`Average Student Loans`)))
    
    sc_time_selective_title <- tags$p(tags$style('p{color:gray; font-size: 14px; family: serif}'),
                            tags$b('Average Debt By State (2019)'))
    leaflet(states_year()) %>% addProviderTiles("CartoDB.Positron") %>%
      addPolygons(fillColor = ~pal(states_year()$`Average Student Loans`),
                  color = "white",
                  weight = 0.5,
                  fillOpacity = 0.7,  
              highlight = highlightOptions(
                weight = 5,
                color = "#666",
                fillOpacity = 0.7,
                bringToFront = TRUE,
                ),popup=pop_pop) %>% addLegend(position = "bottomleft", colors =c("#EDF8E9","#BAE4B3","#74C476","#31A354","#006D2C"), 
                     labels = c(paste('$',round(min(states_year()$`Average Student Loans`)))," "," "," ", 
                                paste('$',round(max(states_year()$`Average Student Loans`)))),
            title = "Average Student Loans (Per Student)") %>%
  leaflet::setView(-98.5795, 39.8282, zoom=3) %>% addControl(sc_time_selective_title, position='topright')
    })
    observe({
    leafletProxy("studentdebtmap", data = states_year())
  }) 
}

shinyApp(ui = ui, server = server)

Listening on http://127.0.0.1:6909
`summarise()` regrouping output by 'STABBR' (override with `.groups` argument)
sf layer has inconsistent datum (+proj=longlat +datum=NAD83 +no_defs).
Need '+proj=longlat +datum=WGS84'n too large, allowed maximum for palette Greens is 9
Returning the palette you asked for with that many colors
`summarise()` regrouping output by 'STABBR' (override with `.groups` argument)
sf layer has inconsistent datum (+proj=longlat +datum=NAD83 +no_defs).
Need '+proj=longlat +datum=WGS84'n too large, allowed maximum for palette Greens is 9
Returning the palette you asked for with that many colors
`summarise()` regrouping output by 'STABBR' (override with `.groups` argument)
sf layer has inconsistent datum (+proj=longlat +datum=NAD83 +no_defs).
Need '+proj=longlat +datum=WGS84'n too large, allowed maximum for palette Greens is 9
Returning the palette you asked for with that many colors
`summarise()` regrouping output by 'STABBR' (override with `.groups` argument)
sf layer has inconsistent datum (+proj=longlat +datum=NAD83 +no_defs).
Need '+proj=longlat +datum=WGS84'n too large, allowed maximum for palette Greens is 9
Returning the palette you asked for with that many colors
`summarise()` regrouping output by 'STABBR' (override with `.groups` argument)
sf layer has inconsistent datum (+proj=longlat +datum=NAD83 +no_defs).
Need '+proj=longlat +datum=WGS84'n too large, allowed maximum for palette Greens is 9
Returning the palette you asked for with that many colors
`summarise()` regrouping output by 'STABBR' (override with `.groups` argument)
sf layer has inconsistent datum (+proj=longlat +datum=NAD83 +no_defs).
Need '+proj=longlat +datum=WGS84'n too large, allowed maximum for palette Greens is 9
Returning the palette you asked for with that many colors
NA
ui <- fluidPage(
  titlePanel('The Cost of Higher Education: An Exploration of Student Debt in American Universities')
  
)
 
LS0tCnRpdGxlOiAiVmlzdWFsc19EcmFmdF8wNF8xNCIKYXV0aG9yOiAiQ29ubmllIFh1IgpkYXRlOiAiNC8xNC8yMDIxIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Kc2V0d2QoIn4vRHJvcGJveCAoQnVzaW5lc3MpL1NwcmluZyAyMDIxL1FNU1MgNTA2MyAtIERhdGEgVmlzdWFsaXphdGlvbiAvR3JvdXBfR19IaWdoZXJFZC9zcmMvdmlzdWFscy8iKQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpCnNvdXJjZSgib3VydGhlbWUuUiIpCmBgYAoKYGBge3IgcGFja2FnZXMsIGVjaG89RkFMU0UsIGV2YWw9VFJVRSwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0KciA9IGdldE9wdGlvbigicmVwb3MiKQpyWyJDUkFOIl0gPSAiaHR0cDovL2NyYW4udXMuci1wcm9qZWN0Lm9yZyIKb3B0aW9ucyhyZXBvcyA9IHIpCiMgaW5zdGFsbC5wYWNrYWdlcyAoYmFzaWMpCnN1cHByZXNzTWVzc2FnZXMobGlicmFyeShkcGx5cikpCnN1cHByZXNzTWVzc2FnZXMobGlicmFyeSh0aWR5dmVyc2UpKQoKIyBpbnN0YWxsLnBhY2thZ2VzIChyZWFkaW5nKQpzdXBwcmVzc01lc3NhZ2VzKGxpYnJhcnkoWE1MKSkKc3VwcHJlc3NNZXNzYWdlcyhsaWJyYXJ5KFJDdXJsKSkKc3VwcHJlc3NNZXNzYWdlcyhsaWJyYXJ5KHJlYWRyKSkKc3VwcHJlc3NNZXNzYWdlcyhsaWJyYXJ5KCJyZWFkeGwiKSkKCiMgaW5zdGFsbC5wYWNrYWdlcyAodGhlbWVzKQpzdXBwcmVzc01lc3NhZ2VzKGxpYnJhcnkoZ2d0aGVtZXMpKQpzdXBwcmVzc01lc3NhZ2VzKGxpYnJhcnkoZ2dyZXBlbCkpCnN1cHByZXNzTWVzc2FnZXMobGlicmFyeShSQ29sb3JCcmV3ZXIpKQpzdXBwcmVzc01lc3NhZ2VzKGxpYnJhcnkodmlyaWRpcykpCnN1cHByZXNzTWVzc2FnZXMobGlicmFyeShocmJydGhlbWVzKSkKc3VwcHJlc3NNZXNzYWdlcyhsaWJyYXJ5KHBsb3RseSkpCgoKIyBpbnN0YWxsLnBhY2thZ2VzIChtYXBzKQpzdXBwcmVzc01lc3NhZ2VzKGxpYnJhcnkoUmdvb2dsZU1hcHMpKQpzdXBwcmVzc01lc3NhZ2VzKGxpYnJhcnkoZ2dtYXApKQpzdXBwcmVzc01lc3NhZ2VzKGluc3RhbGwucGFja2FnZXMoIm1hcHMiKSkKc3VwcHJlc3NNZXNzYWdlcyhpbnN0YWxsLnBhY2thZ2VzKCJ0bWFwIikpICMgaW5zdGFsbCB0aGUgQ1JBTiB2ZXJzaW9uCnN1cHByZXNzTWVzc2FnZXMobGlicmFyeSh0bWFwKSkKc3VwcHJlc3NNZXNzYWdlcyhpbnN0YWxsLnBhY2thZ2VzKCdyZ2VvcycpKQoKc3VwcHJlc3NNZXNzYWdlcyhsaWJyYXJ5KGRldnRvb2xzKSkKIyBMZXQncyBpbnN0YWxsIHRoZSBkZXZlbG9wbWVudCB2ZXJzaW9uIGZyb20gR2l0aHViLiBSdW4KZGV2dG9vbHM6Omluc3RhbGxfZ2l0aHViKCJyc3R1ZGlvL2xlYWZsZXQiKQpgYGAKCmBgYHtyIGltcG9ydCBnZW5lcmFsIGRhdGEsIGVjaG89VFJVRSwgZXZhbD1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojIFNldCB0aGUgV0QgYXMgR3JvdXBfR19IaWdoZXJFZCAKc2V0d2QoIn4vRHJvcGJveCAoQnVzaW5lc3MpL1NwcmluZyAyMDIxL1FNU1MgNTA2MyAtIERhdGEgVmlzdWFsaXphdGlvbiAvR3JvdXBfR19IaWdoZXJFZCIpCgojIFdoaWxlIG91ciBpbml0aWFsIENvbGxlZ2UgU2NvcmVjYXJkIG9ubHkgaW5jbHVkZWQgMjAxOSBpbml0aWFsbHksIEkgd2FzIGFibGUgdG8gcnVuIGEgc2ltcGxlIHB5dGhvbiBzY3JpcHQgdG8gY29uY2F0ZW5hdGUgYW5kIHNlbGVjdCBhIHNtYWxsIG51bWJlciBvZiByZWxldmFudCBjb2x1bW5zIGZvciBvdXIgdmlzdWFsaXphdGlvbiBhbmQgYW5hbHlzaXMuIFRodXMsIGFzIG91ciBmaXJzdCB2aXN1YWxpemF0aW9ucyBvbmx5IHVuY2x1ZGUgMjAxOSwgdGhlIGNvZGUgYmVsb3cgaXMgZm9yIHJlLWZpbHRlcmluZyB0aGUgY29uY2F0ZW5hdGVkIDIwMTAtMjAxOSBkYXRhIGJhY2sgaW50byBzaW1wbHkgMjAxOS4gCgpzY190aW1lIDwtIHJlYWRfY3N2KCdzcmMvMjAxMF8yMDE5X3N0dWRlbnRfZGVidC5jc3YnKSAKc2MgPC0gc2NfdGltZSAlPiUgZmlsdGVyKFllYXJfRW5kaW5nID09IDIwMTkpCgpsaWJyYXJ5KGVkdWNhdGlvbmRhdGEpCiMgVGVzdCBSdW4gd2l0aCB1c2luZyBnZXRfZWR1Y2F0aW9uX2RhdGEgCiMgZGF0YSA8LSBnZXRfZWR1Y2F0aW9uX2RhdGEobGV2ZWwgPSAiY29sbGVnZS11bml2ZXJzaXR5IiwKIyAgICAgc291cmNlID0gImlwZWRzIiwKIyAgICAgdG9waWMgPSAiZGlyZWN0b3J5IiwKIyAgICAgZmlsdGVycyA9IGxpc3QoeWVhciA9IDIwMTkpKQojIGRhdGEKIyBTY29yZWNhcmQgZGF0YSAtIDIwMTkgCgojIyBjaGFuZ2UgcHJvamVjdGlvbiBvZiBzYyBkYXRhCnNjIDwtIHNjICU+JQogIGRwbHlyOjptdXRhdGUodW5pX3JhbmsgPSBjYXNlX3doZW4oCiAgICBBRE1fUkFURSA8IDAuMiB+ICdoaWdobHkgc2VsZWN0aXZlL2VsaXRlJywKICAgIEFETV9SQVRFIDwgMC4zIH4gJ21vcmUgc2VsZWN0aXZlJywKICAgIEFETV9SQVRFIDwgMC41IH4gJ3NlbGVjdGl2ZScsCiAgICBBRE1fUkFURSA8IDAuNyB+ICdsZXNzIHNlbGVjdGl2ZScsCiAgICBUUlVFIH4gJ25vdCBzZWxlY3RpdmUnKSkgJT4lIG11dGF0ZSh1bmlfcmFuayA9IGZhY3Rvcih1bmlfcmFuaywgbGV2ZWxzPWMoJ25vdCBzZWxlY3RpdmUnLCAnbGVzcyBzZWxlY3RpdmUnLCAnc2VsZWN0aXZlJywgJ21vcmUgc2VsZWN0aXZlJywgJ2hpZ2hseSBzZWxlY3RpdmUvZWxpdGUnKSkpCmBgYAoKIyMgU2ltcGxlIFNjYXR0ZXJncmFtIAoKRmlyc3Qgd2UgYXJlIGdvaW5nIHRvIHRyeSB0byBwcmVzZW50IHRoaXMgcGF0dGVybiBmb3IgZGlmZmVyZW50IHRpZXJzIG9mIHVuaXZlcnNpdGllcyAoYWRtaXNzaW9uIHJhdGUgYXMgd2VsbCBhcyBkZWJ0KQpgYGB7ciwgZWNobz1UUlVFLCBldmFsPVRSVUV9CiMgUmVtb3ZlIFByaXZhY3lTdXBwcmVzc2VkIFJlY29yZHMgYW5kIHRyYW5zZm9ybSBEZWJ0IE1lZGlhbiBpbnRvIGEgbnVtZXJpYyB2YWx1ZSAtIHdlIGNhbiBhbHNvIGRvIHRoaXMgb24gdGhlIG1haW4gc2MgZGYKc2MkREVCVF9NRE5baXMubmEoc2MkREVCVF9NRE4pXSA8LSAwOwoKYnJld2VyLnBhbChuPTEwLCJQdUJ1R24iKQpTaG9ydFB1QnVHbiA8LSBjKCIjRDBEMUU2IiwiI0E2QkREQiIsIiM2N0E5Q0YiLCIjMzY5MEMwIiwiIzAyODE4QSIpCgptIDwtIHNjICU+JSBzdWJzZXQoREVCVF9NRE4gIT0nUHJpdmFjeVN1cHByZXNzZWQnKSAlPiUgdHJhbnNmb3JtKERFQlRfTUROID0gYXMubnVtZXJpYyhERUJUX01ETikpICU+JSAKICAgICAgICAgICAgICBnZ3Bsb3QoLiwgYWVzKHg9QURNX1JBVEUsIHk9REVCVF9NRE4sY29sb3I9dW5pX3JhbmspKSArCiAgZ2VvbV9wb2ludChwY2g9MjEpICsKICBnZW9tX3Ntb290aChjb2xvcj0nbmF2eScsIHNlID0gRkFMU0UpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPVNob3J0UHVCdUduKSsKICB0aGVtZSgKICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLAogICAgcGFuZWwuYmFja2dyb3VuZD0gZWxlbWVudF9yZWN0KGZpbGw9IndoaXRlIikpICsKICBzY2FsZV95X2Rpc2NyZXRlKGxpbWl0cz1jKDAsMTAwMDAsMjAwMDAsMzAwMDApLCBsYWJlbHM9YygnMCcsJzEwJywnMjAnLCczMCcpKSArCiAgbGFicyh4PSdBZG1pc3Npb25zIFJhdGUnLCB5PSdNZWRpYW4gTG9hbiBBbW91bnQgcGVyIFN0dWRlbnRcbih0aG91c2FuZHMpJywgCiAgICAgICB0aXRsZT0nU3R1ZGVudCBEZWJ0IGFuZCBBZG1pc3Npb25zIFJhdGUnLAogICAgICAgY29sb3I9J1NlbGVjdGl2aXR5JykKbQpgYGAKClRoaXMgaXMgYSBkYXRhIHRhYmxlIHNob3dpbmcgdGhlIGJyZWFrZG93biBvZiB0aGUgdW5pdmVyc2l0eSByYW5rcyAoYXMgSSBjaG9zZSB0byByYW5rIHRoZW0pLiBJIHdpbGwgbm90ZSB0aGF0IGZyb20gdGhlIGR0IGFsb25lIHd3ZSBhcmUgc2VlaW5nIGEgZG93bndhcmQgdHJlbmQgaW4gdGhlICdNZWRpYW4gU3R1ZGVudCBMb2FucycgY29sdW1uLiAKYGBge3IsIGVjaG89VFJVRSwgZXZhbD1UUlVFfQojIENyZWF0ZSBEYXRhIFRhYmxlIChTdW1tYXJpemVkKSBmb3IgCmxpYnJhcnkoJ3NjYWxlcycpCgpzY19kdCA8LSBzYyAlPiUgc3Vic2V0KERFQlRfTUROICE9J1ByaXZhY3lTdXBwcmVzc2VkJykgJT4lIHRyYW5zZm9ybShERUJUX01ETiA9IGFzLm51bWVyaWMoREVCVF9NRE4pKSAlPiUgZ3JvdXBfYnkodW5pX3JhbmspICU+JSBtdXRhdGUoYE51bWJlciBvZiBVbml2ZXJzaXRpZXNgID0gbigpKSAlPiUgdW5ncm91cCgpICU+JSBtdXRhdGUoREVCVF9NRE5fU1RVREVOVFMgPSBERUJUX01ETipVR0RTKSAlPiUgZ3JvdXBfYnkodW5pX3JhbmspICU+JSBtdXRhdGUoYE1lZGlhbiBTdHVkZW50IExvYW5zYCA9IHBhc3RlKCckJyxyb3VuZChzdW0oREVCVF9NRE5fU1RVREVOVFMsIG5hLnJtPVRSVUUpL3N1bShVR0RTLCBuYS5ybT1UUlVFKSwyKSkpICU+JSAKICBtdXRhdGUoYE1pbiBBY2NlcHRhbmNlIFJhdGVgID0gcGVyY2VudChtaW4oQURNX1JBVEUpKSkgJT4lIG11dGF0ZShgTWF4IEFjY2VwdGFuY2UgUmF0ZWAgPSBwZXJjZW50KG1heChBRE1fUkFURSkpKSAlPiUgdW5ncm91cCgpICU+JSAKICBncm91cF9ieSh1bmlfcmFuayxgTWVkaWFuIFN0dWRlbnQgTG9hbnNgLGBOdW1iZXIgb2YgVW5pdmVyc2l0aWVzYCxgTWluIEFjY2VwdGFuY2UgUmF0ZWAsYE1heCBBY2NlcHRhbmNlIFJhdGVgKSAlPiUgCiAgc3VtbWFyaXplKCkKCmluc3RhbGwucGFja2FnZXMoJ0RUJykKbGlicmFyeShEVCkKdGFibGUgPC0gZGF0YXRhYmxlKHNjX2R0LHN0eWxlID0gImRlZmF1bHQiLGZpbHRlciA9ICd0b3AnLCAgY2FwdGlvbiA9ICdVbml2ZXJzaXRpZXMgYW5kIFNlbGVjdGl2aXR5JykKdGFibGUKCmBgYApgYGB7cn0KaW5zdGFsbC5wYWNrYWdlcygndHJlZW1hcCcpCmluc3RhbGwucGFja2FnZXMoJ2hpZ2hjaGFydGVyJykKbGlicmFyeShoaWdoY2hhcnRlcikKbGlicmFyeSh0cmVlbWFwKQoKc2NfZHQgJT4lIAogIHRyZWVtYXAoaW5kZXg9InVuaV9yYW5rIiwKICAgICAgICAgIHZTaXplPSJOdW1iZXIgb2YgVW5pdmVyc2l0aWVzIiwKICAgICAgICB0eXBlPSJpbmRleCIsCiAgICAgICAgZm9udHNpemUubGFiZWxzPWMoMTIsIDgpLCAKICAgICAgICBwYWxldHRlID0gIHZpcmlkaXMoNSksCiAgICAgICAgYm9yZGVyLmNvbD0id2hpdGUiLAogICAgICAgIHRpdGxlID0gJ1VuaXZlcnNpdGllcyBhbmQgU2VsZWN0aXZpdHknKQpgYGAKCgojIyBTY2F0dGVyZ3JhbSBhcyBWaW9saW4gUGxvdApgYGB7ciwgZWNobz1UUlVFLCBldmFsPVRSVUV9Cm0gPC0gc2MgJT4lIHN1YnNldChERUJUX01ETiAhPSdQcml2YWN5U3VwcHJlc3NlZCcpICU+JSB0cmFuc2Zvcm0oREVCVF9NRE4gPSBhcy5udW1lcmljKERFQlRfTUROKSkgJT4lIAogIGdncGxvdCguLCBhZXMoeD11bmlfcmFuaywgeT1ERUJUX01ETikpICsKICBnZW9tX3Zpb2xpbihhZXMoZmlsbD11bmlfcmFuayxjb2xvcj11bmlfcmFuaykpICsKICBnZW9tX2JveHBsb3Qod2lkdGggPSAwLjIpKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1TaG9ydFB1QnVHbikgKwogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzPVNob3J0UHVCdUduKSArCiAgdGhlbWUoCiAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLAogICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIHBhbmVsLmJhY2tncm91bmQ9IGVsZW1lbnRfcmVjdChmaWxsPSJ3aGl0ZSIpKSsKICBzY2FsZV95X2Rpc2NyZXRlKGxpbWl0cz1jKDAsMTAwMDAsMjAwMDAsMzAwMDApLCBsYWJlbHM9YygnMCcsJzEwJywnMjAnLCczMCcpKSArCiAgc2NhbGVfeF9kaXNjcmV0ZShsYWJlbHM9Yygnbm90XG5zZWxlY3RpdmVcbig+NzAlKScsJ2xlc3NcbnNlbGVjdGl2ZVxuKDUwJS03MCUpJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICdzZWxlY3RpdmVcbigzMCUtNTAlKScsJ21vcmVcbnNlbGVjdGl2ZVxuKDIwJS0zMCUpJywnaGlnaGx5XG5zZWxlY3RpdmVcbig1JS0yMCUpJywnZWxpdGVcbig8NSUpJykpICsKCiAgbGFicyh4PSdTZWxlY3Rpdml0eVxuKGFkbWlzc2lvbiByYXRlIHRocmVzaG9sZHMpJywgeT0nTWVkaWFuIExvYW4gQW1vdW50IHBlciBTdHVkZW50XG4odGhvdXNhbmRzKScsIAogICAgICAgdGl0bGU9J1NlbGVjdGl2ZSBTY2hvb2xzIGFuZCBTdHVkZW50IERlYnQnLAogICAgICAgY29sb3I9JycsZmlsbD0nJykKbQpgYGAKU2hvd2luZyB0aGUgcHJldmlvdXMgc2NhdHRlcmdyYW0gc3BlY2lmaWNhbGx5IGFzIHZpb2xpbmcgcGxvdHMKCmBgYHtyLCBlY2hvPVRSVUUsIGV2YWw9VFJVRX0KaXBlZHMxNSA8LSBnZXRfZWR1Y2F0aW9uX2RhdGEobGV2ZWwgPSAiY29sbGVnZS11bml2ZXJzaXR5IiwKICAgIHNvdXJjZSA9ICJpcGVkcyIsCiAgICB0b3BpYyA9ICJncmFkLXJhdGVzLXBlbGwiLAogICAgZmlsdGVycyA9IGxpc3QoeWVhciA9IDIwMTUpKQppcGVkczE1CmBgYAoKCiMjIFN0dWRlbnQgRGVidCBvdmVyIFRpbWUKCmBgYHtyLCBlY2hvPVRSVUUsIGV2YWw9VFJVRX0KCiNQcm9jZXNzIHRoZSBkYXRhIApzY190aW1lIDwtIHJlYWRfY3N2KCcyMDEwXzIwMTlfc3R1ZGVudF9kZWJ0LmNzdicpIAoKc2NfdGltZTwtIHNjX3RpbWUgJT4lIHN1YnNldChERUJUX01ETiAhPSdQcml2YWN5U3VwcHJlc3NlZCcpICU+JSAKICB0cmFuc2Zvcm0oREVCVF9NRE4gPSBhcy5udW1lcmljKERFQlRfTUROKSkgJT4lIAogIGRwbHlyOjptdXRhdGUoREVCVF9NRE4gPSBpZmVsc2UoaXMubmEoREVCVF9NRE4pLCAwLCBERUJUX01ETikpCgpgYGAKCgpgYGB7ciwgZWNobz1UUlVFLCBldmFsPVRSVUV9CiNQcm9jZXNzIHRoZSBkYXRhIApzZXR3ZCgifi9Ecm9wYm94IChCdXNpbmVzcykvU3ByaW5nIDIwMjEvUU1TUyA1MDYzIC0gRGF0YSBWaXN1YWxpemF0aW9uIC9Hcm91cF9HX0hpZ2hlckVkIikKc2NfdGltZSA8LSByZWFkX2Nzdignc3JjLzIwMTBfMjAxOV9zdHVkZW50X2RlYnQuY3N2JykgCnNjX3RpbWU8LSBzY190aW1lICU+JSBzdWJzZXQoREVCVF9NRE4gIT0nUHJpdmFjeVN1cHByZXNzZWQnKSAlPiUgCiAgdHJhbnNmb3JtKERFQlRfTUROID0gYXMubnVtZXJpYyhERUJUX01ETikpICU+JSAKICBkcGx5cjo6bXV0YXRlKERFQlRfTUROID0gaWZlbHNlKGlzLm5hKERFQlRfTUROKSwgMCwgREVCVF9NRE4pKSAlPiUgCiAgbXV0YXRlKERFQlRfTUROX1NUVURFTlQgPSBERUJUX01ETipVR0RTKQpzY190aW1lCgpzdW0oc2NfdGltZSRVR0RTLG5hLnJtPVRSVUUpCmBgYAoKQmVsb3cgaXMgYW4gaW50ZXJhY3RpdmUgbGluZSBncmFwaCAoMjAxMC0yMDE5KSB3aGljaCBkZXRhaWxzIHRoZSB0cmVuZHMgaW4gc3R1ZGVudCBkZWJ0IG92ZXIgdGhlIHllYXJzLiAKYGBge3IsIGVjaG89VFJVRSwgZXZhbD1UUlVFfQojIENQSSBJbmZsYXRpb24gUmF0ZXMgLSBHb3QgQXZlcmFnZSBZZWFybHkgSW5mbGF0aW9uIFJhdGUgZm9yIFNjYWxpbmcgZm9yIFN0dWRlbnQgRGVidCAKaW5zdGFsbC5wYWNrYWdlcygncXVhbnRtb2QnKQpsaWJyYXJ5KHF1YW50bW9kKQpnZXRTeW1ib2xzKCJDUElBVUNTTCIsIHNyYz0nRlJFRCcpCmF2Zy5jcGkgPC0gYXBwbHkueWVhcmx5KENQSUFVQ1NMLCBtZWFuKQpjZiA8LSBhcy5kYXRhLmZyYW1lKGF2Zy5jcGkvYXMubnVtZXJpYyhhdmcuY3BpWycyMDA5J10pKSAKY2YkWWVhcl9FbmRpbmcgPC0gZm9ybWF0KGFzLkRhdGUocm93Lm5hbWVzKGNmKSwgZm9ybWF0PSIlWS0lbS0lZCIpLCIlWSIpCgojIE1lcmdlZCBmb3IgSW5mbGF0aW9uIApzY190aW1lX2RmIDwtIHNjX3RpbWUgJT4lIGdyb3VwX2J5KGBZZWFyX0VuZGluZ2ApICU+JSBtdXRhdGUoYEF2ZXJhZ2UgQW5udWFsIFN0dWRlbnQgRGVidCAtIE5hdGlvbmFsYCA9IHN1bShERUJUX01ETl9TVFVERU5ULG5hLnJtPVRSVUUpL3N1bShVR0RTLG5hLnJtPVRSVUUpKSAlPiUgdW5ncm91cCgpICU+JSAKICBkcGx5cjo6bXV0YXRlKHVuaV9yYW5rID0gY2FzZV93aGVuKAogICAgQURNX1JBVEUgPCAwLjIgfiAnZWxpdGUvaGlnaGx5IHNlbGVjdGl2ZScsCiAgICBBRE1fUkFURSA8IDAuMyB+ICdtb3JlIHNlbGVjdGl2ZScsCiAgICBBRE1fUkFURSA8IDAuNSB+ICdzZWxlY3RpdmUnLAogICAgQURNX1JBVEUgPCAwLjcgfiAnbGVzcyBzZWxlY3RpdmUnLAogICAgVFJVRSB+ICdub3Qgc2VsZWN0aXZlJykpICU+JQogIG11dGF0ZSh1bmlfcmFuayA9IGZhY3Rvcih1bmlfcmFuaywgbGV2ZWxzPWMoJ25vdCBzZWxlY3RpdmUnLCAnbGVzcyBzZWxlY3RpdmUnLCAnc2VsZWN0aXZlJywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnbW9yZSBzZWxlY3RpdmUnLCAnZWxpdGUvaGlnaGx5IHNlbGVjdGl2ZScpKSkgJT4lCiAgZ3JvdXBfYnkodW5pX3JhbmssWWVhcl9FbmRpbmcpICU+JSAKICBtdXRhdGUoYEF2ZXJhZ2UgQW5udWFsIFN0dWRlbnQgRGVidCAoYnkgU2VsZWN0aXZpdHkpYCA9IHN1bShERUJUX01ETl9TVFVERU5ULG5hLnJtPVRSVUUpL3N1bShVR0RTLG5hLnJtPVRSVUUpKSAlPiUgCiAgdW5ncm91cCgpICU+JSAKICBncm91cF9ieShgWWVhcl9FbmRpbmdgLGBBdmVyYWdlIEFubnVhbCBTdHVkZW50IERlYnQgKGJ5IFNlbGVjdGl2aXR5KWAsCiAgICAgICAgICAgdW5pX3JhbmssYEF2ZXJhZ2UgQW5udWFsIFN0dWRlbnQgRGVidCAtIE5hdGlvbmFsYCkgJT4lIHN1bW1hcml6ZSgpICU+JSAKICBtZXJnZShjZikgJT4lIAogIG11dGF0ZShgQWRqdXN0ZWQgQXZlcmFnZSBBbm51YWwgU3R1ZGVudCBEZWJ0YCA9IGBBdmVyYWdlIEFubnVhbCBTdHVkZW50IERlYnQgKGJ5IFNlbGVjdGl2aXR5KWAvCiAgICAgICAgICAgQ1BJQVVDU0wpICU+JSAKICBtdXRhdGUoYEFkanVzdGVkIEF2ZXJhZ2UgQW5udWFsIFN0dWRlbnQgRGVidCAtIENvbXBvc2l0ZWAgPSBgQXZlcmFnZSBBbm51YWwgU3R1ZGVudCBEZWJ0IC0gTmF0aW9uYWxgLwogICAgICAgICAgIENQSUFVQ1NMKQoKc2NfZGYgPC0gc2NfdGltZV9kZiAlPiUgZ3JvdXBfYnkoYEF2ZXJhZ2UgQW5udWFsIFN0dWRlbnQgRGVidCAtIE5hdGlvbmFsYCxgQWRqdXN0ZWQgQXZlcmFnZSBBbm51YWwgU3R1ZGVudCBEZWJ0IC0gQ29tcG9zaXRlYCxZZWFyX0VuZGluZykgJT4lIHN1bW1hcml6ZSgpICU+JSBtdXRhdGUodW5pX3Jhbms9J25hdGlvbmFsIGF2ZXJhZ2UnKSAlPiUgbXV0YXRlKGBBZGp1c3RlZCBBdmVyYWdlIEFubnVhbCBTdHVkZW50IERlYnRgPWBBZGp1c3RlZCBBdmVyYWdlIEFubnVhbCBTdHVkZW50IERlYnQgLSBDb21wb3NpdGVgKSAlPiUgZHBseXI6Om11dGF0ZShgQXZlcmFnZSBBbm51YWwgU3R1ZGVudCBEZWJ0IChieSBTZWxlY3Rpdml0eSlgID0gYEF2ZXJhZ2UgQW5udWFsIFN0dWRlbnQgRGVidCAtIE5hdGlvbmFsYCkgJT4lIG1lcmdlKGNmKSAlPiUgc2VsZWN0KFllYXJfRW5kaW5nLGBBdmVyYWdlIEFubnVhbCBTdHVkZW50IERlYnQgKGJ5IFNlbGVjdGl2aXR5KWAsIHVuaV9yYW5rLCBgQXZlcmFnZSBBbm51YWwgU3R1ZGVudCBEZWJ0IC0gTmF0aW9uYWxgLCBDUElBVUNTTCwgYEFkanVzdGVkIEF2ZXJhZ2UgQW5udWFsIFN0dWRlbnQgRGVidGAsYEFkanVzdGVkIEF2ZXJhZ2UgQW5udWFsIFN0dWRlbnQgRGVidCAtIENvbXBvc2l0ZWApCnNjX3RpbWVfZGYgPC0gc2NfdGltZV9kZiAlPiUgcmJpbmQoc2NfZGYpICU+JSBtdXRhdGUodW5pX3JhbmsgPSBmYWN0b3IodW5pX3JhbmssIGxldmVscz1jKCduYXRpb25hbCBhdmVyYWdlJywnbm90IHNlbGVjdGl2ZScsICdsZXNzIHNlbGVjdGl2ZScsICdzZWxlY3RpdmUnLCAnbW9yZSBzZWxlY3RpdmUnLCAnZWxpdGUvaGlnaGx5IHNlbGVjdGl2ZScpKSkgJT4lIAogIG11dGF0ZShuYXRpb25hbCA9IGlmZWxzZSh1bmlfcmFuayA9PSAnbmF0aW9uYWwgYXZlcmFnZScsICd5JywnbicpKQpzY19kZgpzY190aW1lX2RmCgoKcCA8LSBzY190aW1lX2RmICU+JSAKICBnZ3Bsb3QoLixhZXMoeD1ZZWFyX0VuZGluZyx5PWBBZGp1c3RlZCBBdmVyYWdlIEFubnVhbCBTdHVkZW50IERlYnRgLCBjb2xvcj11bmlfcmFuaywgZ3JvdXA9bmF0aW9uYWwpKSArIAogIGdlb21fcG9pbnQoKSArIGdlb21fbGluZShhZXMobGluZXR5cGU9bmF0aW9uYWwpKSArIAogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygnZ3JleScsIiNEMEQxRTYiLCIjQTZCRERCIiwiIzY3QTlDRiIsIiMzNjkwQzAiLCIjMDI4MThBIikpKwogIHRoZW1lKAogICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICBwYW5lbC5iYWNrZ3JvdW5kPSBlbGVtZW50X3JlY3QoZmlsbD0id2hpdGUiKSkgKwogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSByb3VuZChzZXEobWluKHNjX3RpbWUkWWVhcl9FbmRpbmcpLCBtYXgoc2NfdGltZSRZZWFyX0VuZGluZyksIGJ5ID0gMiksMSkpICsKICBsYWJzKHg9JycsIHk9J0luZmxhdGlvbi1BZGp1c3RlZCBNZWRpYW4gTG9hbiBBbW91bnQgcGVyIFN0dWRlbnRcbih0aG91c2FuZHMpJywgCiAgICAgICB0aXRsZT0nU3R1ZGVudCBEZWJ0IEhhcyBCZWVuIFJpc2luZyBPdmVyIFRoZSBZZWFycycsCiAgICAgICBjb2xvcj0nJyxmaWxsPScnLGdyb3VwPScnLGxpbmV0eXBlPScnKQpnZ3Bsb3RseShwKQoKCmBgYAoKVGhlIGZvbGxvd2luZyBpcyAoaW5zdGVhZCkgYSBiYXIgZ3JhcGggd2l0aCBmZXdlciAndW5pdmVyc2l0eSBzZWxlY3Rpdml0eScgYnVja2V0cy4gCmBgYHtyfQpzY190aW1lX2RmIDwtIHNjX3RpbWUgJT4lIGdyb3VwX2J5KGBZZWFyX0VuZGluZ2ApICU+JSBtdXRhdGUoYEF2ZXJhZ2UgQW5udWFsIFN0dWRlbnQgRGVidCAtIE5hdGlvbmFsYCA9IHN1bShERUJUX01ETl9TVFVERU5ULG5hLnJtPVRSVUUpL3N1bShVR0RTLG5hLnJtPVRSVUUpKSAlPiUgdW5ncm91cCgpICU+JSAKICBkcGx5cjo6bXV0YXRlKHVuaV9yYW5rID0gY2FzZV93aGVuKAogICAgQURNX1JBVEUgPCAwLjIgfiAnaGlnaGx5IHNlbGVjdGl2ZScsCiAgICBBRE1fUkFURSA8IDAuNSB+ICdtb2RlcmF0ZWx5IHNlbGVjdGl2ZScsCiAgICBUUlVFIH4gJ2xlc3Mvbm90IGF0IGFsbCBzZWxlY3RpdmUnKSkgJT4lCiAgbXV0YXRlKHVuaV9yYW5rID0gZmFjdG9yKHVuaV9yYW5rLCBsZXZlbHM9YygnbGVzcy9ub3QgYXQgYWxsIHNlbGVjdGl2ZScsICdtb2RlcmF0ZWx5IHNlbGVjdGl2ZScsICdoaWdobHkgc2VsZWN0aXZlJykpKSAlPiUKICBncm91cF9ieSh1bmlfcmFuayxZZWFyX0VuZGluZykgJT4lIAogIG11dGF0ZShgQXZlcmFnZSBBbm51YWwgU3R1ZGVudCBEZWJ0IChieSBTZWxlY3Rpdml0eSlgID0gc3VtKERFQlRfTUROX1NUVURFTlQsbmEucm09VFJVRSkvc3VtKFVHRFMsbmEucm09VFJVRSkpICU+JSAKICB1bmdyb3VwKCkgJT4lIAogIGdyb3VwX2J5KGBZZWFyX0VuZGluZ2AsYEF2ZXJhZ2UgQW5udWFsIFN0dWRlbnQgRGVidCAoYnkgU2VsZWN0aXZpdHkpYCwKICAgICAgICAgICB1bmlfcmFuayxgQXZlcmFnZSBBbm51YWwgU3R1ZGVudCBEZWJ0IC0gTmF0aW9uYWxgKSAlPiUgc3VtbWFyaXplKCkgJT4lIAogIG1lcmdlKGNmKSAlPiUgCiAgbXV0YXRlKGBBZGp1c3RlZCBBdmVyYWdlIEFubnVhbCBTdHVkZW50IERlYnRgID0gYEF2ZXJhZ2UgQW5udWFsIFN0dWRlbnQgRGVidCAoYnkgU2VsZWN0aXZpdHkpYC8KICAgICAgICAgICBDUElBVUNTTCkgJT4lIAogIG11dGF0ZShgQWRqdXN0ZWQgQXZlcmFnZSBBbm51YWwgU3R1ZGVudCBEZWJ0IC0gQ29tcG9zaXRlYCA9IGBBdmVyYWdlIEFubnVhbCBTdHVkZW50IERlYnQgLSBOYXRpb25hbGAvCiAgICAgICAgICAgQ1BJQVVDU0wpCgpzY19kZiA8LSBzY190aW1lX2RmICU+JSBncm91cF9ieShgQXZlcmFnZSBBbm51YWwgU3R1ZGVudCBEZWJ0IC0gTmF0aW9uYWxgLGBBZGp1c3RlZCBBdmVyYWdlIEFubnVhbCBTdHVkZW50IERlYnQgLSBDb21wb3NpdGVgLFllYXJfRW5kaW5nKSAlPiUgc3VtbWFyaXplKCkgJT4lIG11dGF0ZSh1bmlfcmFuaz0nbmF0aW9uYWwgYXZlcmFnZScpICU+JSBtdXRhdGUoYEFkanVzdGVkIEF2ZXJhZ2UgQW5udWFsIFN0dWRlbnQgRGVidGA9YEFkanVzdGVkIEF2ZXJhZ2UgQW5udWFsIFN0dWRlbnQgRGVidCAtIENvbXBvc2l0ZWApICU+JSBkcGx5cjo6bXV0YXRlKGBBdmVyYWdlIEFubnVhbCBTdHVkZW50IERlYnQgKGJ5IFNlbGVjdGl2aXR5KWAgPSBgQXZlcmFnZSBBbm51YWwgU3R1ZGVudCBEZWJ0IC0gTmF0aW9uYWxgKSAlPiUgbWVyZ2UoY2YpICU+JSBzZWxlY3QoWWVhcl9FbmRpbmcsYEF2ZXJhZ2UgQW5udWFsIFN0dWRlbnQgRGVidCAoYnkgU2VsZWN0aXZpdHkpYCwgdW5pX3JhbmssIGBBdmVyYWdlIEFubnVhbCBTdHVkZW50IERlYnQgLSBOYXRpb25hbGAsIENQSUFVQ1NMLCBgQWRqdXN0ZWQgQXZlcmFnZSBBbm51YWwgU3R1ZGVudCBEZWJ0YCxgQWRqdXN0ZWQgQXZlcmFnZSBBbm51YWwgU3R1ZGVudCBEZWJ0IC0gQ29tcG9zaXRlYCkKc2NfdGltZV9kZiA8LSBzY190aW1lX2RmICU+JSByYmluZChzY19kZikgJT4lIG11dGF0ZSh1bmlfcmFuayA9IGZhY3Rvcih1bmlfcmFuaywgbGV2ZWxzPWMoJ25hdGlvbmFsIGF2ZXJhZ2UnLCdsZXNzL25vdCBhdCBhbGwgc2VsZWN0aXZlJywgJ21vZGVyYXRlbHkgc2VsZWN0aXZlJywgJ2hpZ2hseSBzZWxlY3RpdmUnKSkpIAoKZmlnMSA8LSBzY190aW1lX2RmICU+JSBwbG90X2x5KHggPSB+WWVhcl9FbmRpbmcsIHkgPSB+YEFkanVzdGVkIEF2ZXJhZ2UgQW5udWFsIFN0dWRlbnQgRGVidGAsIHR5cGUgPSAnYmFyJywKICBjb2xvciA9IH51bmlfcmFuaywgYWxwaGE9MC44LCBob3ZlcnRlbXBsYXRlID0gJ0F2ZXJhZ2UgRGVidC9TdHVkZW50IChVU0QpOiAle3l9IDxleHRyYT48L2V4dHJhPicsY29sb3JzPSdQdXJwbGVzJykgJT4lIAogIGxheW91dCh5YXhpcyA9IGxpc3QoCiAgdGl0bGUgPSAiQXZlcmFnZSBBbm51YWwgU3R1ZGVudCBEZWJ0IHBlciBTdHVkZW50XG4oQWRqdXN0ZWQgZm9yIEluZmxhdGlvbikiKSkKCmZpZzEKCmBgYAoKQ2hsb3JvcGxldGggc2hvd2luZyBhdmVyYWdlIHN0dWRlbnQgZGVidCAodGhpcyBpcyBvbmx5IDIwMTkgYnV0IEkgaGF2ZSBhIGZpbHRlciBhdCB0aGUgYmVnaW5uaW5nIHRoYXQgd2lsbCBhbGxvdyBtZSB0byBpbmNvcnBvcmF0ZSBhIHNsaWRlciBmb3IgdGhlIHllYXIpLgoKYGBge3IgU3R1ZGVudCBEZWJ0IG1hcCAtIENobG9yb3BsZXRoLCBlY2hvPVRSVUUsIGV2YWw9VFJVRSB9CgojIEFkZGl0aW9ucyBvZiBTdGF0ZXMgZGYgZnJvbSBUaWdyaXMgRmlsZSAKbGlicmFyeSh0aWdyaXMpCgpzdGF0ZXMgPC0gc3RhdGVzKGNiID0gVFJVRSkKCiMgQ2FuIGNoYW5nZSB0byBzY190aW1lX3llYXIgCnNjX3RpbWVfMjAxOSA8LSBzY190aW1lICU+JSBzdWJzZXQoWWVhcl9FbmRpbmcgPSAyMDE5KSAlPiUgCiAgZ3JvdXBfYnkoU1RBQkJSKSAlPiUgbXV0YXRlKGBBdmVyYWdlIFN0dWRlbnQgTG9hbnNgPXN1bShERUJUX01ETl9TVFVERU5ULG5hLnJtPVRSVUUpL3N1bShVR0RTLG5hLnJtPVRSVUUpKSAlPiUgZ3JvdXBfYnkoU1RBQkJSLGBBdmVyYWdlIFN0dWRlbnQgTG9hbnNgKSAlPiUgc3VtbWFyaXplKCkKCiMgU3RhdGVzIApzdGF0ZXNfMjAxOSA8LSBzdGF0ZXMgJT4lIAogIGlubmVyX2pvaW4oc2NfdGltZV8yMDE5LCBieT1jKFNUVVNQUz0nU1RBQkJSJykpIAoKCmxpYnJhcnkobGVhZmxldC5wcm92aWRlcnMpCmxpYnJhcnkobGVhZmxldCkKI3VzZWQgJ3N1Y2Nlc3MnIG1lYXN1cmVzLiAKCnBhbCA9IGNvbG9yRmFjdG9yKCdHcmVlbnMnLCBkb21haW4gPSBzdGF0ZXNfMjAxOSRgQXZlcmFnZSBTdHVkZW50IExvYW5zYCkKCnBvcF9wb3AgPC0gcGFzdGUoIlN0YXRlOiIsc3RhdGVzXzIwMTkkTkFNRSwiPGJyLz4iLAogICAgICAgICAgICAgICAgICJBdmVyYWdlIFN0dWRlbnQgTG9hbnMiLCI8YnIvPiIsCiAgICAgICAgICAgICAgICAgIm9mIFNjaG9vbHMgTG9jYXRlZCBpbiBTdGF0ZToiLHBhc3RlKCckJyxyb3VuZChzdGF0ZXNfMjAxOSRgQXZlcmFnZSBTdHVkZW50IExvYW5zYCkpKQpsaWJyYXJ5KGh0bWx3aWRnZXRzKQpsaWJyYXJ5KGh0bWx0b29scykKc3RhdGVzXzIwMTlfdGl0bGUgPC0gdGFncyRwKHRhZ3Mkc3R5bGUoJ3B7Y29sb3I6Z3JheTsgZm9udC1zaXplOiAxNHB4OyBmYW1pbHk6IHNlcmlmfScpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgdGFncyRiKCdBdmVyYWdlIERlYnQgQnkgU3RhdGUgKDIwMTkpJykpCgpsZWFmbGV0KHN0YXRlc18yMDE5KSAlPiUgYWRkUHJvdmlkZXJUaWxlcygiQ2FydG9EQi5Qb3NpdHJvbiIpICU+JQogIGFkZFBvbHlnb25zKGZpbGxDb2xvciA9IH5wYWwoc3RhdGVzXzIwMTkkYEF2ZXJhZ2UgU3R1ZGVudCBMb2Fuc2ApLAogICAgICAgICAgICAgIGNvbG9yID0gIndoaXRlIiwKICAgICAgICAgICAgICB3ZWlnaHQgPSAwLjUsCiAgICAgICAgICAgICAgZmlsbE9wYWNpdHkgPSAwLjcsICAKICAgICAgICAgICAgICBoaWdobGlnaHQgPSBoaWdobGlnaHRPcHRpb25zKAogICAgICAgICAgICAgICAgd2VpZ2h0ID0gNSwKICAgICAgICAgICAgICAgIGNvbG9yID0gIiM2NjYiLAogICAgICAgICAgICAgICAgZmlsbE9wYWNpdHkgPSAwLjcsCiAgICAgICAgICAgICAgICBicmluZ1RvRnJvbnQgPSBUUlVFLAogICAgICAgICAgICAgICAgKSxwb3B1cD1wb3BfcG9wKSAlPiUgYWRkTGVnZW5kKHBvc2l0aW9uID0gImJvdHRvbWxlZnQiLCBjb2xvcnMgPWMoIiNFREY4RTkiLCIjQkFFNEIzIiwiIzc0QzQ3NiIsIiMzMUEzNTQiLCIjMDA2RDJDIiksIAogICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKHBhc3RlKCckJyxyb3VuZChtaW4oc3RhdGVzXzIwMTkkYEF2ZXJhZ2UgU3R1ZGVudCBMb2Fuc2ApKSksIiAiLCIgIiwiICIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhc3RlKCckJyxyb3VuZChtYXgoc3RhdGVzXzIwMTkkYEF2ZXJhZ2UgU3R1ZGVudCBMb2Fuc2ApKSkpLAogICAgICAgICAgICB0aXRsZSA9ICJBdmVyYWdlIFN0dWRlbnQgTG9hbnMgKFBlciBTdHVkZW50KSIpICU+JQogIGxlYWZsZXQ6OnNldFZpZXcoLTk4LjU3OTUsIDM5LjgyODIsIHpvb209MykgJT4lIGFkZENvbnRyb2woc3RhdGVzXzIwMTlfdGl0bGUsIHBvc2l0aW9uPSd0b3ByaWdodCcpCj9hZGRMZWdlbmQKYGBgCgpgYGB7cn0KYnJld2VyLnBhbChuID0gOCwgbmFtZSA9ICJSZFlsR24iKQpgYGAKCmBgYHtyIFN0dWRlbnQgRGVidCBNYXAgLSBwb2ludHMsIGVjaG89VFJVRSwgZXZhbD1UUlVFIH0KIyBsYXN0IGVkaXQgdG8gc2NfdGltZV8yMDE5IGluIGNodW5rIGFib3ZlIGZvciBjaGxvcm9wbGV0aApzY190aW1lXzIwMTlfc2VsZWN0aXZlIDwtIHNjX3RpbWVfMjAxOSAlPiUgZHBseXI6OnJlbmFtZShsYXQgPSBMQVRJVFVERSkgJT4lIGRwbHlyOjpyZW5hbWUobG9uZyA9IExPTkdJVFVERSkgJT4lIAogIGRwbHlyOjpyZW5hbWUoc3RhdGUgPSBTVEFCQlIpICU+JSBmaWx0ZXIoQURNX1JBVEUgPCAwLjMpICU+JSAKICBkcGx5cjo6bXV0YXRlKHVuaV9yYW5rID0gY2FzZV93aGVuKAogICAgQURNX1JBVEUgPCAwLjA1IH4gJ2VsaXRlJywKICAgIEFETV9SQVRFIDwgMC4yIH4gJ2hpZ2hseSBzZWxlY3RpdmUnLAogICAgVFJVRSB+ICdzZWxlY3RpdmUnKSkKc2NfdGltZV8yMDE5X3NlbGVjdGl2ZSA8LSBzY190aW1lXzIwMTlfc2VsZWN0aXZlICU+JSBzdWJzZXQoREVCVF9NRE4gIT0nUHJpdmFjeVN1cHByZXNzZWQnKSAlPiUgCiAgdHJhbnNmb3JtKERFQlRfTUROID0gYXMubnVtZXJpYyhERUJUX01ETikpICU+JSAKICBkcGx5cjo6bXV0YXRlKERFQlRfTUROID0gaWZlbHNlKGlzLm5hKERFQlRfTUROKSwgMCwgREVCVF9NRE4pKSAKCgoKcGFsMSA9IGNvbG9yRmFjdG9yKFNob3J0UHVCdUduLCBkb21haW4gPSBzY190aW1lXzIwMTlfc2VsZWN0aXZlJGB1bmlfcmFua2AscmV2ZXJzZT1UUlVFKQoKI3NldCBwb3B1cHMgCmNvbnRlbnQgPC0gcGFzdGUoIlNjaG9vbCIsc2NfdGltZV8yMDE5X3NlbGVjdGl2ZSRJTlNUTk0sIjxici8+IiwKICAgICAgICAgICAgICAgICAiTnVtYmVyIG9mIFVuZGVyZ3JhZHM6IixzY190aW1lXzIwMTlfc2VsZWN0aXZlJFVHRFMsIjxici8+IiwKICAgICAgICAgICAgICAgICAiU2VsZWN0aXZpdHk6Iiwgc2NfdGltZV8yMDE5X3NlbGVjdGl2ZSR1bmlfcmFuaywiPGJyLz4iLAogICAgICAgICAgICAgICAgICJNZWRpYW4gRGVidDoiLHBhc3RlKCckJyxyb3VuZChzY190aW1lXzIwMTlfc2VsZWN0aXZlJERFQlRfTUROLDIpKSwiPGJyLz4iKQpzY190aW1lXzIwMTlfc2VsZWN0aXZlCmxlYWZsZXQoc2NfdGltZV8yMDE5X3NlbGVjdGl2ZSkgJT4lIGFkZFRpbGVzKCdodHRwOi8ve3N9LmJhc2VtYXBzLmNhcnRvY2RuLmNvbS9kYXJrX2FsbC97en0ve3h9L3t5fS5wbmcnKSAlPiUKICBhZGRDaXJjbGVzKGNvbCA9IH5wYWwxKHNjX3RpbWVfMjAxOV9zZWxlY3RpdmUkdW5pX3JhbmspLAogICAgICAgICAgICAgcmFkaXVzID0gfkRFQlRfTUROLAogICAgICAgICAgICAgcG9wdXAgPSBjb250ZW50LAogICAgICAgICAgICAgZmlsbE9wYWNpdHkgPSAwLjcpICU+JQogIGxlYWZsZXQ6OmFkZExlZ2VuZChwb3NpdGlvbiA9ICJib3R0b21sZWZ0IixwYWwgPSBwYWwxLCB2YWx1ZXMgPSBzY190aW1lXzIwMTlfc2VsZWN0aXZlJHVuaV9yYW5rLAogICAgICAgICAgICB0aXRsZSA9ICJBdmVyYWdlIFN0dWRlbnQgTG9hbnMgKFBlciBTdHVkZW50KSIpCj9hZGRMZWdlbmQKYGBgCmBgYHtyfQpzZXR3ZCgnfi9Ecm9wYm94IChCdXNpbmVzcykvU3ByaW5nIDIwMjEvUU1TUyA1MDYzIC0gRGF0YSBWaXN1YWxpemF0aW9uIC9Hcm91cF9HX0hpZ2hlckVkLycpCnNjX3RpbWUgPC0gcmVhZF9jc3YoJ3NyYy8yMDEwXzIwMTlfc3R1ZGVudF9kZWJ0LmNzdicpIApzY190aW1lCmBgYAoKVGhlIGNvZGUgY2h1bmsgYmVsb3cgaGFzIG5vdCBiZWVuIHRvdWNoZWQgYW5kIGluY2x1ZGVzIFNoaW55IGNvZGUgZm9yIGxhdGVyIHVzZS4gCmBgYHtyfQpzZXR3ZCgifi9Ecm9wYm94IChCdXNpbmVzcykvU3ByaW5nIDIwMjEvUU1TUyA1MDYzIC0gRGF0YSBWaXN1YWxpemF0aW9uIC9Hcm91cF9HX0hpZ2hlckVkIikKc2NfdGltZSA8LSByZWFkX2Nzdignc3JjLzIwMTBfMjAxOV9zdHVkZW50X2RlYnQuY3N2JykgCnNjX3RpbWU8LSBzY190aW1lICU+JSBzdWJzZXQoREVCVF9NRE4gIT0nUHJpdmFjeVN1cHByZXNzZWQnKSAlPiUgCiAgdHJhbnNmb3JtKERFQlRfTUROID0gYXMubnVtZXJpYyhERUJUX01ETikpICU+JSAKICBkcGx5cjo6bXV0YXRlKERFQlRfTUROID0gaWZlbHNlKGlzLm5hKERFQlRfTUROKSwgMCwgREVCVF9NRE4pKSAlPiUgCiAgbXV0YXRlKERFQlRfTUROX1NUVURFTlQgPSBERUJUX01ETipVR0RTKQpzY190aW1lCgpsaWJyYXJ5KHJlc2hhcGUyKQpsaWJyYXJ5KHNoaW55KQp1aSA8LSBmbHVpZFBhZ2UoCiAgdGl0bGVQYW5lbCgiSSBsb3ZlIEdyYXBocyBhYm91dCBTdHVkZW50IERlYnQiKSwKICAjIHNlbGVjdElucHV0KCd5ZWFyJywKICAjICdZZWFyJywKICAjIGNob2ljZXM9YygyMDEwLDIwMTEsMjAxMiwyMDEzLDIwMTQsMjAxNSwyMDE2LDIwMTcsMjAxOCwyMDE5KSksIAogIHNsaWRlcklucHV0KGlucHV0SWQgPSAieWVhciIsCiAgbGFiZWwgPSAiWWVhciIsCiAgdmFsdWUgPSBjKDIwMTAsMjAxMSwyMDEyLDIwMTMsMjAxNCwyMDE1LDIwMTYsMjAxNywyMDE4LDIwMTkpKSwKICBsZWFmbGV0T3V0cHV0KCJzdHVkZW50ZGVidG1hcCIpCgopCgpzZXJ2ZXIgPC0gZnVuY3Rpb24oaW5wdXQsIG91dHB1dCwgc2Vzc2lvbil7CiAgIyBSZW5kZXIgcGxvdCBvZiB0b3AgMTAgbW9zdCBwb3B1bGFyIG5hbWVzCiAgICBzY190aW1lX3NlbGVjdGl2ZSA8LSByZWFjdGl2ZSh7c2NfdGltZSAlPiUgc3Vic2V0KFllYXJfRW5kaW5nID09IGlucHV0JHllYXIpICU+JSAKICAgICAgICBncm91cF9ieShTVEFCQlIpICU+JSBtdXRhdGUoYEF2ZXJhZ2UgU3R1ZGVudCBMb2Fuc2A9c3VtKERFQlRfTUROX1NUVURFTlQsbmEucm09VFJVRSkvc3VtKFVHRFMsbmEucm09VFJVRSkpICU+JQogICAgICAgIGdyb3VwX2J5KFNUQUJCUixgQXZlcmFnZSBTdHVkZW50IExvYW5zYCkgJT4lIHN1bW1hcml6ZSgpfSkKICAgIGxpYnJhcnkodGlncmlzKQogICAgc3RhdGVzIDwtIHN0YXRlcyhjYiA9IFRSVUUpCiAgICBzdGF0ZXNfeWVhciA8LSByZWFjdGl2ZSh7c3RhdGVzICU+JSBpbm5lcl9qb2luKHNjX3RpbWVfc2VsZWN0aXZlKCksIGJ5PWMoU1RVU1BTPSdTVEFCQlInKSl9KSAKICAgIAogIG91dHB1dCRzdHVkZW50ZGVidG1hcCA8LSByZW5kZXJMZWFmbGV0KHsKICAgIHBhbCA9IGNvbG9yRmFjdG9yKCdHcmVlbnMnLCBkb21haW4gPSBzdGF0ZXNfeWVhcigpJGBBdmVyYWdlIFN0dWRlbnQgTG9hbnNgKQogICAgcG9wX3BvcCA8LSBwYXN0ZSgiU3RhdGU6IixzdGF0ZXNfeWVhcigpJE5BTUUsIjxici8+IiwKICAgICAgICAgICAgICAgICAgICAgIkF2ZXJhZ2UgU3R1ZGVudCBMb2FucyIsIjxici8+IiwgIm9mIFNjaG9vbHMgTG9jYXRlZCBpbiBTdGF0ZToiLAogICAgICAgICAgICAgICAgICAgICBwYXN0ZSgnJCcscm91bmQoc3RhdGVzX3llYXIoKSRgQXZlcmFnZSBTdHVkZW50IExvYW5zYCkpKQogICAgCiAgICBzY190aW1lX3NlbGVjdGl2ZV90aXRsZSA8LSB0YWdzJHAodGFncyRzdHlsZSgncHtjb2xvcjpncmF5OyBmb250LXNpemU6IDE0cHg7IGZhbWlseTogc2VyaWZ9JyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0YWdzJGIoJ0F2ZXJhZ2UgRGVidCBCeSBTdGF0ZSAoMjAxOSknKSkKICAgIGxlYWZsZXQoc3RhdGVzX3llYXIoKSkgJT4lIGFkZFByb3ZpZGVyVGlsZXMoIkNhcnRvREIuUG9zaXRyb24iKSAlPiUKICAgICAgYWRkUG9seWdvbnMoZmlsbENvbG9yID0gfnBhbChzdGF0ZXNfeWVhcigpJGBBdmVyYWdlIFN0dWRlbnQgTG9hbnNgKSwKICAgICAgICAgICAgICAgICAgY29sb3IgPSAid2hpdGUiLAogICAgICAgICAgICAgICAgICB3ZWlnaHQgPSAwLjUsCiAgICAgICAgICAgICAgICAgIGZpbGxPcGFjaXR5ID0gMC43LCAgCiAgICAgICAgICAgICAgaGlnaGxpZ2h0ID0gaGlnaGxpZ2h0T3B0aW9ucygKICAgICAgICAgICAgICAgIHdlaWdodCA9IDUsCiAgICAgICAgICAgICAgICBjb2xvciA9ICIjNjY2IiwKICAgICAgICAgICAgICAgIGZpbGxPcGFjaXR5ID0gMC43LAogICAgICAgICAgICAgICAgYnJpbmdUb0Zyb250ID0gVFJVRSwKICAgICAgICAgICAgICAgICkscG9wdXA9cG9wX3BvcCkgJT4lIGFkZExlZ2VuZChwb3NpdGlvbiA9ICJib3R0b21sZWZ0IiwgY29sb3JzID1jKCIjRURGOEU5IiwiI0JBRTRCMyIsIiM3NEM0NzYiLCIjMzFBMzU0IiwiIzAwNkQyQyIpLCAKICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYyhwYXN0ZSgnJCcscm91bmQobWluKHN0YXRlc195ZWFyKCkkYEF2ZXJhZ2UgU3R1ZGVudCBMb2Fuc2ApKSksIiAiLCIgIiwiICIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhc3RlKCckJyxyb3VuZChtYXgoc3RhdGVzX3llYXIoKSRgQXZlcmFnZSBTdHVkZW50IExvYW5zYCkpKSksCiAgICAgICAgICAgIHRpdGxlID0gIkF2ZXJhZ2UgU3R1ZGVudCBMb2FucyAoUGVyIFN0dWRlbnQpIikgJT4lCiAgbGVhZmxldDo6c2V0VmlldygtOTguNTc5NSwgMzkuODI4Miwgem9vbT0zKSAlPiUgYWRkQ29udHJvbChzY190aW1lX3NlbGVjdGl2ZV90aXRsZSwgcG9zaXRpb249J3RvcHJpZ2h0JykKICAgIH0pCiAgICBvYnNlcnZlKHsKICAgIGxlYWZsZXRQcm94eSgic3R1ZGVudGRlYnRtYXAiLCBkYXRhID0gc3RhdGVzX3llYXIoKSkKICB9KSAKfQoKc2hpbnlBcHAodWkgPSB1aSwgc2VydmVyID0gc2VydmVyKQoKYGBgCgpgYGB7cn0KdWkgPC0gZmx1aWRQYWdlKAogIHRpdGxlUGFuZWwoJ1RoZSBDb3N0IG9mIEhpZ2hlciBFZHVjYXRpb246IEFuIEV4cGxvcmF0aW9uIG9mIFN0dWRlbnQgRGVidCBpbiBBbWVyaWNhbiBVbml2ZXJzaXRpZXMnKQogIAopCiAKYGBgCgo=